home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 22 / Cream of the Crop 22.iso / program / recio215.zip / RECIO.C < prev    next >
C/C++ Source or Header  |  1996-10-26  |  15KB  |  409 lines

  1. /*****************************************************************************
  2.    MODULE: recio.c
  3.   PURPOSE: record input/output functions
  4. COPYRIGHT: (C) 1994-1996, William Pierpoint
  5.  COMPILER: Borland C Version 3.1
  6.        OS: MSDOS Version 6.2
  7.   VERSION: 2.15
  8.   RELEASE: October 26, 1996
  9. *****************************************************************************/
  10.  
  11. #include <ctype.h>
  12. #include <errno.h>
  13. #include <float.h>
  14. #include <limits.h>
  15. #include <stdio.h>
  16. #include <stdlib.h>
  17. #include <string.h>
  18.  
  19. #include "recio.h"
  20.  
  21. #define rcol(rp)         ((rp)->r_colno)
  22. #define rflags(rp)       ((rp)->r_flags)
  23. #define rfd(rp)          ((rp)->r_fd)
  24. #define rfp(rp)          ((rp)->r_fp)
  25. #define rreclen(rp)      ((rp)->r_reclen)
  26. #define rrecsiz(rp)      ((rp)->r_recsiz)
  27. #define rfldsiz(rp)      ((rp)->r_fldsiz)
  28. #define rfldch(rp)       ((rp)->r_fldch)
  29. #define rtxtch(rp)       ((rp)->r_txtch)
  30. #define rtmfmt(rp)       ((rp)->r_tmfmt)
  31.  
  32. /* private module variables */
  33. static REC *_RECS = NULL;              /* ptr to array of RECs */
  34. static char _tmfmt[] = "%m/%d/%y";     /* default time format string */
  35.  
  36. static REC rin  = { 1,      0,    stdin,  "stdin",     0L,
  37.                     0,      0,        0,        0,   NULL, 
  38.                     0,   NULL, RECFLDCH, RECTXTCH,  _tmfmt, RECIN };
  39.  
  40. static REC rout = { 2, _R_WRT,   stdout, "stdout",     0L, 
  41.                     0,      0,        0,        0,   NULL, 
  42.                     0,   NULL, RECFLDCH, RECTXTCH, _tmfmt, RECOUT };
  43.  
  44. static REC rerr = { 3, _R_WRT,   stderr, "stderr",     0L, 
  45.                     0,      0,        0,        0,   NULL, 
  46.                     0,   NULL, RECFLDCH, RECTXTCH, _tmfmt, RECERR };
  47.  
  48. #if (R_NREC >= 4)
  49. static REC rprn = { 4, _R_WRT,   stdprn, "stdprn",     0L, 
  50.                     0,      0,        0,        0,   NULL, 
  51.                     0,   NULL, RECFLDCH, RECTXTCH, _tmfmt, RECPRN };
  52. #endif
  53.  
  54. #define ROPEN_MIN R_NREC       /* reserved for recin, etc */
  55. #define ROPEN     max(ROPEN_MAX, ROPEN_MIN)
  56.  
  57. /* public variables */
  58. REC *recin = &rin;
  59. REC *recout = &rout;
  60. REC *recerr = &rerr;
  61. #if (R_NREC >= 4)
  62. REC *recprn = &rprn;
  63. #endif
  64.  
  65. /* friend variables */
  66. char _r_nsbuf[NSBUFSIZ];     /* buffer for numeric to string conversions */
  67. void (*_r_errfn)(REC *);     /* pointer to error message function */
  68.  
  69. /* Support functions */
  70. /****************************************************************************/
  71. static void                  /* returns nothing                             */
  72.     _rexit(                  /* at program exit, clean up                   */
  73.         void)                /* no arguments                                */
  74. /****************************************************************************/
  75. {
  76.     /* free recin buffers */
  77.     free(rflds(recin));
  78.     free(rrecs(recin));
  79.     rflds(recin) = NULL;
  80.     rfldsiz(recin) = 0;
  81.     rrecs(recin) = NULL;
  82.     rrecsiz(recin) = 0;
  83.     rreclen(recin) = 0;
  84.  
  85.     /* ensure all record streams closed */
  86.     rcloseall();
  87. }
  88.  
  89. /****************************************************************************/
  90. void                         /* return error number (0=no error)            */
  91.     _rsetexitfn(             /* register _rexit function with atexit()      */
  92.         REC *rp)             /* record pointer                              */
  93. /****************************************************************************/
  94. {
  95.     static int once=0;       /* register exit fn only once */
  96.  
  97.     if (!once) {
  98.  
  99.         /* execute this path at most one time */
  100.         once++;
  101.  
  102.         /* if atexit() fails to register _rexit() function */
  103.         if (atexit(_rexit)) {
  104.  
  105.            /* register warning */
  106.            rsetwarn(rp, R_WNOREG);
  107.         }
  108.     }
  109.  
  110. /****************************************************************************/
  111. int                          /* return error number (0=no error)            */
  112.     _rmoderror(              /* check for mode error                        */
  113.         REC *rp,             /* record pointer                              */
  114.         int mode)            /* mode (0=read; !0=write/append)              */
  115. /****************************************************************************/
  116. {
  117.     int errnum=0;            /* error number (0=mode ok, !0=invalid mode) */
  118.     unsigned smode;          /* stream mode */
  119.  
  120.     /* if stream _R_WRT flag does not match mode */
  121.     smode = rflags(rp) & _R_WRT;
  122.     if ((mode && !smode) || (!mode && smode)) {
  123.         errnum = rseterr(rp, R_EINVMOD);
  124.     }
  125.     return errnum;
  126. }
  127.  
  128. /****************************************************************************/
  129. int                          /* return !0 if ready; 0 if in error state     */
  130.     _risready(               /* see if record stream is ready               */
  131.         REC *rp,             /* record pointer                              */
  132.         int mode)            /* mode (0=read; !0=write/append)              */
  133. /****************************************************************************/
  134. {
  135.     int errnum=0;            /* error number */
  136.  
  137.     /* test for valid record pointer */
  138.     if (!risvalid(rp)) {
  139.         errnum = rseterr(NULL, EINVAL);
  140.         goto done;
  141.     }
  142.     
  143.     /* check mode */
  144.     errnum = _rmoderror(rp, mode);
  145.     if (errnum) goto done;
  146.  
  147.     /* if record 0 and write mode, set record number to 1 */
  148.     if (!rrecno(rp) && mode) rrecno(rp)++;
  149.  
  150.     /* test for any previous error */
  151.     errnum = rerror(rp);
  152.  
  153. done:
  154.     return (!(errnum));
  155. }
  156.  
  157. /****************************************************************************/
  158. static void                  /* returns nothing                             */
  159.     _rfree(                  /* free the memory allocated to a record       */
  160.         REC *rp)             /* record pointer                              */
  161. /****************************************************************************/
  162. {
  163.     if (risvalid(rp)) {
  164.         free(rflds(rp));
  165.         free(rrecs(rp));
  166.         if (rfp(rp)) fclose(rfp(rp));
  167.         memset(rp, 0, sizeof(REC));
  168.     }
  169. }
  170.  
  171. /* User functions */
  172. /****************************************************************************/
  173. REC *                        /* return record pointer                       */
  174.     ropen(                   /* open a record stream for reading            */
  175.         const char *fname,   /* name of file to open                        */
  176.         const char *mode)    /* type of mode used to open file              */
  177. /****************************************************************************/
  178. {
  179.     REC *rp = _RECS;         /* record pointer */
  180.     int  i;                  /* count of REC structures */
  181.     int  ch;                 /* first character of mode */
  182.     
  183.     errno = 0;
  184.  
  185.     /* only modes currently supported are "r", "w", and "a" */
  186.     ch = tolower(*mode);
  187.     if (!(ch=='r' || ch=='w' || ch=='a')) {
  188.         rp = NULL;
  189.         rseterr(NULL, EINVAL);
  190.         goto done;
  191.     }
  192.  
  193.     /* allocate memory for array of REC structures */
  194.     if (!rp) {
  195.         do {
  196.             /* note: no memory allocation needed for recin, etc */
  197.             rp = _RECS = (REC *) calloc(ROPEN-R_NREC, sizeof(REC));
  198.             if (!rp) {
  199.                 if (rseterr(NULL, ENOMEM)) goto done;
  200.             }
  201.         } while (!rp);
  202.     }
  203.  
  204.     /* search thru REC structures until empty position found */
  205.     for (i=R_NREC+1; i <= ROPEN; i++, rp++) {
  206.         if (!rfd(rp)) {
  207.             rfd(rp) = i;
  208.             break;
  209.         }
  210.     }
  211.     /* error if out of positions */
  212.     if (i > ROPEN) {
  213.         rp = NULL;
  214.         rseterr(NULL, EMFILE);
  215.         goto done;
  216.     }
  217.  
  218.     /* open file */
  219.     rfp(rp) = fopen(fname, mode);
  220.     if (!rfp(rp)) {
  221.         rclose(rp);
  222.         rp = NULL;
  223.         /* if error other than path/file not found */
  224.         if (errno != ENOENT) {
  225.             rseterr(NULL, errno);
  226.         }
  227.         goto done;
  228.     }
  229.  
  230.     /* initialize */
  231.     rflags(rp)  = 0;
  232.     if (ch != 'r') rflags(rp) |= _R_WRT;
  233.     rnames(rp)  = fname;
  234.     rrecno(rp)  = 0L;
  235.     rfldno(rp)  = 0;
  236.     rcol(rp)    = 0;
  237.     rrecsiz(rp) = 0;
  238.     rreclen(rp) = 0;
  239.     rrecs(rp)   = NULL;
  240.     rfldsiz(rp) = 0;
  241.     rflds(rp)   = NULL;
  242.     rfldch(rp)  = RECFLDCH;
  243.     rtxtch(rp)  = RECTXTCH;
  244.     rtmfmt(rp) = _tmfmt;
  245.     rcxtno(rp) = 0;
  246.     _rsetexitfn(rp);
  247.  
  248. done:
  249.     return rp;
  250. }
  251.  
  252. /****************************************************************************/
  253. void                         /* returns nothing                             */
  254.     rclose(                  /* close a record stream                       */
  255.         REC *rp)             /* record pointer                              */
  256. /****************************************************************************/
  257. {
  258.     int i;                   /* count REC structures */
  259.     REC *recp=_RECS;         /* pointer to _RECS array */
  260.  
  261.     if (risvalid(rp)) {
  262.         /* close record stream, but not recin, recout, recerr */
  263.         if (rfd(rp) > R_NREC) _rfree(rp);
  264.  
  265.         /* if all record streams closed, free _RECS */
  266.         /* note: valid rp implies valid recp */
  267.         for (i=R_NREC+1; i <= ROPEN; i++, recp++) {
  268.             if (rfd(recp)) goto done;
  269.         }
  270.         free(_RECS);
  271.         _RECS = NULL;
  272.  
  273.     } else {
  274.         rseterr(NULL, EINVAL);
  275.     }
  276.  
  277. done:
  278.     return;
  279. }
  280.  
  281. /****************************************************************************/
  282. int                          /* returns number of streams closed            */
  283.     rcloseall(               /* close all record streams                    */
  284.         void)                /* no arguments                                */
  285. /****************************************************************************/
  286. {
  287.     int num=0;               /* number of streams closed */
  288.     int i;                   /* count REC structures */
  289.     REC *recp=_RECS;         /* pointer to _RECS array */
  290.  
  291.     /* close every open record stream, except recin, etc */
  292.     if (recp) {
  293.         for (i=R_NREC+1; i <= ROPEN; i++, recp++) {
  294.             if (rfd(recp)) {
  295.                 _rfree(recp);
  296.                 num++;
  297.             }
  298.         }
  299.         free(_RECS);
  300.         _RECS = NULL;
  301.     }
  302.     return num;
  303. }
  304.  
  305. /****************************************************************************/
  306. int                          /* return !0 for valid; 0 for invalid          */
  307.     risvalid(                /* is record pointer valid?                    */
  308.         REC *rp)             /* record pointer                              */
  309. /****************************************************************************/
  310. {
  311.     int valid=1;             /* validation state (!0=valid) */
  312.  
  313.     /* if rp is null pointer or rfd not between 1 and ROPEN */
  314.     if (!rp || rfd(rp) < 1 || rfd(rp) > ROPEN) {
  315.         /* invalid record pointer */
  316.         valid = 0;
  317.     }
  318.     return valid;
  319. }
  320.  
  321. /****************************************************************************/
  322. void                         /* returns nothing                             */
  323.     rsetfldch(               /* set field separator character               */
  324.         REC *rp,             /* record pointer                              */
  325.         int  ch)             /* field separator character                   */
  326. /****************************************************************************/
  327. {
  328.     if (risvalid(rp)) {
  329.         if (isascii(ch)) {
  330.             rfldch(rp) = ch;
  331.         } else {
  332.             rseterr(rp, R_EINVAL);
  333.         }
  334.     } else {
  335.         rseterr(NULL, EINVAL);
  336.     }
  337. }
  338.  
  339. /****************************************************************************/
  340. void                         /* returns nothing                             */
  341.     rsettxtch(               /* set text string delimiter character         */
  342.         REC *rp,             /* record pointer                              */
  343.         int  ch)             /* text delimiter character                    */
  344. /****************************************************************************/
  345. {
  346.     if (risvalid(rp)) {
  347.         if (isascii(ch)) {
  348.             rtxtch(rp) = ch;
  349.         } else {
  350.             rseterr(rp, R_EINVAL);
  351.         }
  352.     } else {
  353.         rseterr(NULL, EINVAL);
  354.     }
  355. }
  356.  
  357. /****************************************************************************/
  358. void                         /* returns nothing                             */
  359.     rsettmfmt(               /* set time format string for record stream    */
  360.         REC *rp,             /* record pointer                              */
  361.         const char *fmt)     /* time format string                          */
  362. /****************************************************************************/
  363. {
  364.     if (risvalid(rp)) {
  365.         rtmfmt(rp) = fmt;
  366.     } else {
  367.         rseterr(NULL, EINVAL);
  368.     }
  369. }
  370.  
  371. /****************************************************************************/
  372. void                         /* returns nothing                             */
  373.     rsetcxtno(               /* set context number of record stream         */
  374.         REC *rp,             /* record pointer                              */
  375.         int  cxtno)          /* context number                              */
  376. /****************************************************************************/
  377. {
  378.     if (risvalid(rp)) {
  379.         if (rcxtno(rp) >= 0  && cxtno >= 0) {
  380.             rcxtno(rp) = cxtno;
  381.         } else {
  382.             rseterr(rp, R_EINVAL);
  383.         }
  384.     } else {
  385.         rseterr(NULL, EINVAL);
  386.     }
  387. }
  388.  
  389. /****************************************************************************/
  390. void                         /* returns nothing                             */
  391.     rsetbegcolno(            /* set beginning record column number          */
  392.         REC *rp,             /* record pointer                              */
  393.         int  colno)          /* first column in record is 0 or 1            */
  394. /****************************************************************************/
  395. {
  396.     if (risvalid(rp)) {
  397.         if (colno == 1) {
  398.             rflags(rp) |= _R_COL;
  399.         } else if (colno == 0) {
  400.             rflags(rp) &= ~_R_COL;
  401.         } else {
  402.             rseterr(rp, R_EINVAL);
  403.         }
  404.     } else {
  405.         rseterr(NULL, EINVAL);
  406.     }
  407. }
  408.